Activity启动分析(二)

在Activity启动流程分析一篇中,我们介绍了从Launcher启动桌面应用的大体流程,本篇将是这一篇的补充,主要分析在Activity准备启动到显示过程中的详细内容,探讨关于WindowManager,Activity以及Window之间的联系。从而更进一步了解Android GUI 子系统。

应用进程创建

Activity启动是在ActivityThread中进行的,通过Zygote创建完应用进程后,首先会通过ActivityThread的main方法初始化UI线程,然后会通知ActivityManager进行attachApplication,这里AMS(ActivityManagerService)会看栈顶是否有等待启动的Activity,如果有的话就通过IApplicationThread通知应用Launch这个Activity。关于这个IApplication它实际是一个Binder,它负责AMS和应用进程之间的通信,在ActivityThread中的一系列schedulexxx方法都是通过这个Binder对象通知的。它的服务端是在应用进程一端,客户端是在AMS所在进程即SystemServer进程中。这个Binder是随着ActivityThread的创建而生成的,并在AMS进行attachApplication时将其传递给AMS。

1
2
3
4
5
6
7
8
9
10
11
12
frameworks/base/core/java/android/app/ActivityThread.java
private void attach(boolean system) {
……
IActivityManager mgr = ActivityManagerNative.getDefault();
try {
//将该ApplicationThread attach到AMS上 因为AMS正是通过这个对象来和应用程序进行binder调用的
mgr.attachApplication(mAppThread);
} catch (RemoteException ex) {
// Ignore
}
……
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
frameworks/base/core/java/android/app/ActivityThread.java
public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
ActivityInfo info, Configuration curConfig, CompatibilityInfo compatInfo,
int procState, Bundle state, List<ResultInfo> pendingResults,
List<Intent> pendingNewIntents, boolean notResumed, boolean isForward,
String profileName, ParcelFileDescriptor profileFd, boolean autoStopProfiler) {//启动activity

updateProcessState(procState, false);

ActivityClientRecord r = new ActivityClientRecord();
r.token = token;
r.ident = ident;
r.intent = intent;
r.activityInfo = info;
……

sendMessage(H.LAUNCH_ACTIVITY, r);
}

AMS通过IApplicationThread的scheduleLaunchActivityl来启动一个Activity,启动过程会对应的创建一个ActivityClientRecord实例,这个和AMS中的ActivityRecord是对应的。这里最为重要的是token参数,它也是一个Binder对象,这个token实际上就是ActivityRecord中的appToken,在ActivityRecord构造时创建,它被AMS用来标记ActivityRecord对应的Activity。在AMS启动过程中会通过WMS调用addAppToken为该Activity添加一个AppWindowToken,appToken作为一个标识被传递给WMS。这样无论是应用进程还是WMS都可以通过这个Token来识别是否为同一个对象。

注:在Android Framework中一个Binder Token通常被用于进行binder通信或者唯一标记一个对象。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
frameworks/base/core/java/android/app/ActivityThread.java
private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent) {
……
Activity a = performLaunchActivity(r, customIntent);

if (a != null) {
……
handleResumeActivity(r.token, false, r.isForward,
!r.activity.mFinished && !r.startsNotResumed);activity显示出来 并回调OnResume
} else {
// If there was an error, for any reason, tell the activity
// manager to stop us.
try {
ActivityManagerNative.getDefault()
.finishActivity(r.token, Activity.RESULT_CANCELED, null);
} catch (RemoteException ex) {
// Ignore
}
}
}

scheduleLaunchActivity 通过H,实际上是个Handler通知调用handleLaunchActivity启动Activity,这个方法首先调用performLaunchActivity创建Activity,然后通过handleResumeActivity显示activity。这两个方法做了Activity启动过程中的绝大部分事情。后面的内容主要据此展开。

Activity的创建

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
frameworks/base/core/java/android/app/ActivityThread.java
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
ActivityInfo aInfo = r.activityInfo;
……
Activity activity = null;
try {
java.lang.ClassLoader cl = r.packageInfo.getClassLoader();//加载ClassLoader
activity = mInstrumentation.newActivity(
cl, component.getClassName(), r.intent);//创建activity
StrictMode.incrementExpectedActivityCount(activity.getClass());
r.intent.setExtrasClassLoader(cl);
if (r.state != null) {
r.state.setClassLoader(cl);
}
} catch (Exception e) {}

try {
Application app = r.packageInfo.makeApplication(false, mInstrumentation);//创建Application
if (activity != null) {
Context appContext = createBaseContextForActivity(r, activity);//为activity 创建ContextImpl对象
CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());
Configuration config = new Configuration(mCompatConfiguration);
//调用activity的attach 将context设置到activity中 保存token
activity.attach(appContext, this, getInstrumentation(), r.token,
r.ident, app, r.intent, r.activityInfo, title, r.parent,
r.embeddedID, r.lastNonConfigurationInstances, config);

if (customIntent != null) {
activity.mIntent = customIntent;
}
r.lastNonConfigurationInstances = null;
activity.mStartedActivity = false;
int theme = r.activityInfo.getThemeResource();//获取activity主题
if (theme != 0) {
activity.setTheme(theme);//将主题将应用到activity
}

activity.mCalled = false;
mInstrumentation.callActivityOnCreate(activity, r.state);//调用activity的onCreate
if (!activity.mCalled) {
throw new SuperNotCalledException(
"Activity " + r.intent.getComponent().toShortString() +
" did not call through to super.onCreate()");
}
r.activity = activity;
r.stopped = true;
if (!r.activity.mFinished) {
activity.performStart();//调用activity的onstart
r.stopped = false;
}
……
}
r.paused = true;

mActivities.put(r.token, r);//保存这个ActivityClientRecord 这在应用端代表了activity

}
……
return activity;
}

在performLaunchActivity中主要做以下事情:

  1. 根据r中的Activity信息创建Activity实例,这个是Instrumention通过反射来完成的。
  2. 为应用创建Application,当然这个Application只会创建一次,如果已经创建了就直接返回
  3. 为Activity创建Context,这里具体为ContextImpl
  4. 将activity attach到上下文Context
  5. 调用onCreate onStart等生命周期回调

接下来我们分步介绍以上几个步骤:

创建Activity实例

创建Activity实例的过程比较简单,因为Activity没有提供任何构造方法,这里通过反射默认构造一个实例。

创建Application

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
//为应用创建application
public Application makeApplication(boolean forceDefaultAppClass,
Instrumentation instrumentation) {
if (mApplication != null) {//Application已经创建就就直接返回
return mApplication;
}

Application app = null;

String appClass = mApplicationInfo.className;//应用设置的application
if (forceDefaultAppClass || (appClass == null)) {//如果应用未设置application或者未强制使用默认的application
appClass = "android.app.Application";//使用默认的application对象
}

try {
java.lang.ClassLoader cl = getClassLoader();
ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);//创建application context
app = mActivityThread.mInstrumentation.newApplication(
cl, appClass, appContext);//创建application
appContext.setOuterContext(app);
} catch (Exception e) {}
mActivityThread.mAllApplications.add(app);
mApplication = app;
……
instrumentation.callApplicationOnCreate(app);
……

return app;
}

makeApplication主要为应用创建Application实例,在创建之前会先通过createAppContext创建AppcliationContext,然后调用onCreate回调。

创建contextImpl

1
2
3
4
5
6
7
8
9
 private Context createBaseContextForActivity(ActivityClientRecord r,
final Activity activity) {
//每个Activity启动时都需要创建一个ContextImpl
ContextImpl appContext = ContextImpl.createActivityContext(this, r.packageInfo, r.token);//创建ContextImpl实例
appContext.setOuterContext(activity);//outerContext实际上为activity
Context baseContext = appContext;
……
return baseContext;
}

每个Acitivty启动都需要为其创建一个Context,这里通过ContextImpl.createActivityContext创建

Activity的attach过程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
frameworks/base/core/java/android/app/Activity.java
final void attach(Context context, ActivityThread aThread,
Instrumentation instr, IBinder token, int ident,
Application application, Intent intent, ActivityInfo info,
CharSequence title, Activity parent, String id,
NonConfigurationInstances lastNonConfigurationInstances,
Configuration config) {
attachBaseContext(context);//context为ContextImpl

mFragments.attachActivity(this, mContainer, null);

mWindow = PolicyManager.makeNewWindow(this);//为其创建窗口 Window为抽象类,这里实际上是创建了PhoneWindow
mWindow.setCallback(this);//设置事件回调
mWindow.getLayoutInflater().setPrivateFactory(this);
if (info.softInputMode != WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED) {
mWindow.setSoftInputMode(info.softInputMode);
}
if (info.uiOptions != 0) {
mWindow.setUiOptions(info.uiOptions);
}
mUiThread = Thread.currentThread();

mMainThread = aThread;
mInstrumentation = instr;
mToken = token;//token赋值 这个token实际上就是在ActivityRecord创建的appToken 它是一个 IApplicationToken.Stub
mIdent = ident;
mApplication = application;
mIntent = intent;
mComponent = intent.getComponent();
mActivityInfo = info;
mTitle = title;
mParent = parent;
mEmbeddedID = id;
mLastNonConfigurationInstances = lastNonConfigurationInstances;
//这里传给window 使用同样的token,这里为window设置一个管理对象,实际是为其创建一个新的WindowManagerImpl
mWindow.setWindowManager(
(WindowManager)context.getSystemService(Context.WINDOW_SERVICE),
mToken, mComponent.flattenToString(),
(info.flags & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0);//设置WindowManager
if (mParent != null) {
mWindow.setContainer(mParent.getWindow());
}
mWindowManager = mWindow.getWindowManager();//取到WindowManager
mCurrentConfig = config;
}

为Activity创建好context后接下来需要调用Activity的attach方法做以下事情:

  1. 设置context,将其保存在ContextWrapper中
  2. 保存token,这个token为ActivityRecord中的appToken
  3. 为Activity创建Window,即PhoneWindow
  4. 为Window设置WindowManager,这个WindowManager实际为WindowManagerImpl。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
frameworks/base/core/java/android/app/ContextImpl.java
class ContextImpl extends Context {
static {
……
registerService(WINDOW_SERVICE, new ServiceFetcher() {
Display mDefaultDisplay;
public Object getService(ContextImpl ctx) {
……
return new WindowManagerImpl(display);
}});
……
}

private static void registerService(String serviceName, ServiceFetcher fetcher) {
……
SYSTEM_SERVICE_MAP.put(serviceName, fetcher);
}

private static final HashMap<String, ServiceFetcher> SYSTEM_SERVICE_MAP =
new HashMap<String, ServiceFetcher>();

@Override
public Object getSystemService(String name) {
ServiceFetcher fetcher = SYSTEM_SERVICE_MAP.get(name);
return fetcher == null ? null : fetcher.getService(this);
}
}

这里需要注意的是contextImpl在getSystemServer(Context.WINDOW_SERVICE)时会创建一个新的实例WindowManagerImpl,所以对于每个Window,都会有一个新的这样的实例。这个WindowManagerImpl并不是WMS的本地代理,这里不要混淆。接下来我们看看在setWindowManager中会做些什么事情

1
2
3
4
5
6
7
8
9
10
11
12
13
public void setWindowManager(WindowManager wm, IBinder appToken, String appName,
boolean hardwareAccelerated) {
mAppToken = appToken;//保存appToken
mAppName = appName;
mHardwareAccelerated = hardwareAccelerated
|| SystemProperties.getBoolean(PROPERTY_HARDWARE_UI, false);
if (wm == null) {
wm = (WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE);
}
//这里的wm实际上是WMS的本地代理,它是在ComtextImpl的getSystemService的ServiceFetcher中注册的
//这里会创建一个新的WindowManagerImpl返回
mWindowManager = ((WindowManagerImpl)wm).createLocalWindowManager(this);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
public final class WindowManagerImpl implements WindowManager {
//单例 事实上所有的接口都是通过WindowManagerGlobal对象完成的
//真正的代理任务是交给WindowManagerGlobal,这个对象是个单例,在一个进程中只有一个
private final WindowManagerGlobal mGlobal = WindowManagerGlobal.getInstance();
private final Display mDisplay;
private final Window mParentWindow;

public WindowManagerImpl(Display display) {
this(display, null);
}

private WindowManagerImpl(Display display, Window parentWindow) {
mDisplay = display;
mParentWindow = parentWindow;
}
//这个在Window的setWindowManager中调用 parentWindow为activity对应的window对象
public WindowManagerImpl createLocalWindowManager(Window parentWindow) {
return new WindowManagerImpl(mDisplay, parentWindow);
}

public WindowManagerImpl createPresentationWindowManager(Display display) {
return new WindowManagerImpl(display, mParentWindow);
}

@Override
public void addView(View view, ViewGroup.LayoutParams params) {
mGlobal.addView(view, params, mDisplay, mParentWindow);
}

@Override
public void updateViewLayout(View view, ViewGroup.LayoutParams params) {
mGlobal.updateViewLayout(view, params);
}

@Override
public void removeView(View view) {
mGlobal.removeView(view, false);
}

@Override
public void removeViewImmediate(View view) {
mGlobal.removeView(view, true);
}

@Override
public Display getDefaultDisplay() {
return mDisplay;
}
}

setWindowManager为该window保存了Activity的appToken,同时通过createLocalWindowManager又创建了一个WindowManagerImpl。这次创建的实例中mParentWindow不为null,而是当前window,需要注意的是它内部持有一个
WindowManagerGlobal单例,这个WindowManagerGlobal是用来和WMS通信的,它内部就持有WMS的Binder本地代理接口对象。

生命周期的回调

Activity完成attach后就已经有对应的PhoneWindow对象了,同时将context保存在activity中了,这时候先回调onCreate,在onCreate中我们通过setContentView设置内容视图,其实是通过PhoneWindow对象的setContentView来完成的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
frameworks/base/policy/src/com/android/internal/policy/impl/PhoneWindow.java
@Override
public void setContentView(int layoutResID) {
if (mContentParent == null) {
installDecor();//创建decorview
} else {
mContentParent.removeAllViews();
}
mLayoutInflater.inflate(layoutResID, mContentParent);
final Callback cb = getCallback();
if (cb != null && !isDestroyed()) {
cb.onContentChanged();
}
}

setContentView为当前window生成一个DecorView,它是整个view树的根view节点。

Activity的显示

通过上面的一系列工作,Activity已经准备好显示前的工作了,接下来就是开始handleResumeActivity了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
final void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward,
boolean reallyResume) {
……
ActivityClientRecord r = performResumeActivity(token, clearHide);//回调OnResume

if (r != null) {
final Activity a = r.activity;
……
if (r.window == null && !a.mFinished && willBeVisible) {//还未被添加到WMS且也没有finish
r.window = r.activity.getWindow();
View decor = r.window.getDecorView();
decor.setVisibility(View.INVISIBLE);
ViewManager wm = a.getWindowManager();
WindowManager.LayoutParams l = r.window.getAttributes();
a.mDecor = decor;
l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;//调整Z主序为TYPE_BASE_APPLICATION 因为默认为TYPE_APPLICATION
l.softInputMode |= forwardBit;
if (a.mVisibleFromClient) {
a.mWindowAdded = true;
wm.addView(decor, l);//添加view decorView是在onCreate中调用setContentView设置的
}
}
……
r.activity.makeVisible();
}
……
}

在这个方法中我们主要看activity是如何被显示出来的。首先获取已经inflate好的DecorView,将其设置为不可见,随后从Activity取到WindowManager(WindowManager是ViewManager的父类,它们都是接口),它实际就是之前通过createLocalWindowManager创建的WindowManagerImpl.随后通过wm.addView添加decorView到window中,这里最终会将window添加到WMS中去。前面我们知道和WMS的通信是由WindowManagerImpl内部的WindowManagerGlobal完成的,它是一个单例。

1
2
3
4
@Override
public void addView(View view, ViewGroup.LayoutParams params) {
mGlobal.addView(view, params, mDisplay, mParentWindow);
}

这里的mParentWindow就是activity对应的window,mDisplay代表显示终端对象。params为view的布局参数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

//具体完成addView接口方法的事务
public void addView(View view, ViewGroup.LayoutParams params,
Display display, Window parentWindow) {
……
ViewRootImpl root;
View panelParentView = null;
synchronized (mLock) {
……

final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams)params;
if (parentWindow != null) {
parentWindow.adjustLayoutParamsForSubWindow(wparams);//设置LayoutParams的token
}
……

root = new ViewRootImpl(view.getContext(), display);//创建ViewRootImpl对象

view.setLayoutParams(wparams);

mViews.add(view);//添加到view列表
mRoots.add(root);//添加到root列表
mParams.add(wparams);//添加到参数列表
}

try {
root.setView(view, wparams, panelParentView);//将view树和viewRoot关联
} catch (RuntimeException e) {}
}

在addView中为当前decorview创建ViewRootImpl,这个是用来管理view树的,对应的将view,root,params分别添加到三个对应的数组中,最后通过ViewRootImpl的setView将当前view和ViewRootImpl关联起来。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) {//关联子视图
synchronized (this) {
if (mView == null) {//未设置view
mView = view;
mViewLayoutDirectionInitial = mView.getRawLayoutDirection();
mFallbackEventHandler.setView(view);
mWindowAttributes.copyFrom(attrs);
……
if ((mWindowAttributes.inputFeatures
& WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {//没有设置InputChannel
mInputChannel = new InputChannel();//输入通道 这个是用来接收事件的 会通过native层设置
}
try {
mOrigWindowType = mWindowAttributes.type;
mAttachInfo.mRecomputeGlobalAttributes = true;
collectViewAttributes();
//将窗口添加到到显示队列中 这个mInputChannel是socketpair的客户端的channel,
res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes,
getHostVisibility(), mDisplay.getDisplayId(),
mAttachInfo.mContentInsets, mInputChannel);
}
……
if (mInputChannel != null) {
if (mInputQueueCallback != null) {
mInputQueue = new InputQueue();
mInputQueueCallback.onInputQueueCreated(mInputQueue);
}
mInputEventReceiver = new WindowInputEventReceiver(mInputChannel,
Looper.myLooper());//创建窗口事件输入接收者 mInputChannel用来接收事件的接口
}
……
// Set up the input pipeline.
//建立输入事件的处理职责链
CharSequence counterSuffix = attrs.getTitle();
InputStage syntheticInputStage = new SyntheticInputStage();
InputStage viewPostImeStage = new ViewPostImeInputStage(syntheticInputStage);
InputStage nativePostImeStage = new NativePostImeInputStage(viewPostImeStage,
"aq:native-post-ime:" + counterSuffix);
InputStage earlyPostImeStage = new EarlyPostImeInputStage(nativePostImeStage);
InputStage imeStage = new ImeInputStage(earlyPostImeStage,
"aq:ime:" + counterSuffix);
InputStage viewPreImeStage = new ViewPreImeInputStage(imeStage);
InputStage nativePreImeStage = new NativePreImeInputStage(viewPreImeStage,
"aq:native-pre-ime:" + counterSuffix);

mFirstInputStage = nativePreImeStage;
mFirstPostImeInputStage = earlyPostImeStage;
mPendingInputEventQueueLengthCounterName = "aq:pending:" + counterSuffix;
}
}
}

ViewRootImpl作为view树的管理者负责view树的绘制和输入事件的管理。其中最重要的工作是通过mWindowSession将当前window添加到WMS中去。这里需要注意mWindow是一个W对象,它是一个Binder对象,WMS使用它和应用进程通信,当窗口状态发生变化需要通过这个Binder通知应用端。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
 //获取windowsession进行会话 也是一个单例 可见一个应用也只会有一个session
public static IWindowSession getWindowSession() {
synchronized (WindowManagerGlobal.class) {
if (sWindowSession == null) {
try {
InputMethodManager imm = InputMethodManager.getInstance();
IWindowManager windowManager = getWindowManagerService();
sWindowSession = windowManager.openSession(
imm.getClient(), imm.getInputContext());//打开会话
float animatorScale = windowManager.getAnimationScale(2);
ValueAnimator.setDurationScale(animatorScale);
} catch (RemoteException e) {
Log.e(TAG, "Failed to open window session", e);
}
}
return sWindowSession;
}
}

mWindowSession是在创建ViewRootImpl通过WindowManagerGlobal的getWindowSession得到的。它返回一个IWindowSession是一个匿名binder,用来和WMS进行会话,在WindowManagerGlobal中它是这样打开一个会话的,它同样是一个单例,即一个应用进程只需要一个会话就可以了。

1
2
3
4
5
6
7
8
9
frameworks/base/services/java/com/android/server/wm/Session.java
//添加window到WMS 应用端通过session来和WMS交互
@Override
public int addToDisplay(IWindow window, int seq, WindowManager.LayoutParams attrs,
int viewVisibility, int displayId, Rect outContentInsets,
InputChannel outInputChannel) {
return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId,
outContentInsets, outInputChannel);
}

得到该会话就可以通过addToDisplay将window添加到WMS了,它实际是和Session交互的,Session是IWindowSession匿名binder的服务端,mService是WMS服务。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
//添加window到WMS 
public int addWindow(Session session, IWindow client, int seq,
WindowManager.LayoutParams attrs, int viewVisibility, int displayId,
Rect outContentInsets, InputChannel outInputChannel) {

boolean reportNewConfig = false;
WindowState attachedWindow = null;//Window在WMS是通过WindowState体现的
WindowState win = null;

synchronized(mWindowMap) {

if (mWindowMap.containsKey(client.asBinder())) {
Slog.w(TAG, "Window " + client + " is already added");
return WindowManagerGlobal.ADD_DUPLICATE_ADD;
}

boolean addToken = false;
WindowToken token = mTokenMap.get(attrs.token);//获取到对应的appWindowToken
if (token == null) {

token = new WindowToken(this, attrs.token, -1, false);
addToken = true;
}

win = new WindowState(this, session, client, token,
attachedWindow, appOp[0], seq, attrs, viewVisibility, displayContent);

mPolicy.adjustWindowParamsLw(win.mAttrs);
win.setShowToOwnerOnlyLocked(mPolicy.checkShowToOwnerOnly(attrs));

res = mPolicy.prepareAddWindowLw(win, attrs);
if (res != WindowManagerGlobal.ADD_OKAY) {
return res;
}

if (outInputChannel != null && (attrs.inputFeatures
& WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
String name = win.makeInputChannelName();
//创建一对输入通道,其中第一个为服务端的channel位于WindowManagerService中,另外一个通过outInputChannel参数返回到应用程序中
InputChannel[] inputChannels = InputChannel.openInputChannelPair(name);
win.setInputChannel(inputChannels[0]);
inputChannels[1].transferTo(outInputChannel);//第二个channel是作为outInputChannel返回给客户端的
//向InputDispatcher注册服务端的channel,这样当Disaptcher收到事件后可以通过该channel分发事件给客户端
mInputManager.registerInputChannel(win.mInputChannel, win.mInputWindowHandle);
}
……
if (addToken) {
mTokenMap.put(attrs.token, token);
}
win.attach();
mWindowMap.put(client.asBinder(), win);

if (type == TYPE_INPUT_METHOD) {
win.mGivenInsetsPending = true;
mInputMethodWindow = win;
addInputMethodWindowToListLocked(win);
imMayMove = false;
} else if (type == TYPE_INPUT_METHOD_DIALOG) {
mInputMethodDialogs.add(win);
addWindowToListInOrderLocked(win, true);
moveInputMethodDialogsLocked(findDesiredInputMethodWindowIndexLocked(true));
imMayMove = false;
} else {
addWindowToListInOrderLocked(win, true);
if (type == TYPE_WALLPAPER) {
mLastWallpaperTimeoutTime = 0;
displayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
} else if ((attrs.flags&FLAG_SHOW_WALLPAPER) != 0) {
displayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
} else if (mWallpaperTarget != null
&& mWallpaperTarget.mLayer >= win.mBaseLayer) {
// If there is currently a wallpaper being shown, and
// the base layer of the new window is below the current
// layer of the target window, then adjust the wallpaper.
// This is to avoid a new window being placed between the
// wallpaper and its target.
displayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
}
}

assignLayersLocked(displayContent.getWindowList());

}

return res;
}

首先我们注意到两个map

1
2
final HashMap<IBinder, WindowState> mWindowMap = new HashMap<IBinder, WindowState>();
final HashMap<IBinder, WindowToken> mTokenMap = new HashMap<IBinder, WindowToken>();

mWindowMap是IWindow和服务端Window的映射,这里WindowState即代表了服务端的Window,而IWindow是ViewRootImpl中的W对象。

mTokenMap是token和WindowToken的映射,这里的token为appToken,windowToken为我们在启动activity之前通过addApptoken添加的。

在addWindow中主要完成以下事情:

  1. 通过token取到WindowToken,这个token来自 WindowManager.LayoutParams,它是在WindowManagerGlobal的addView中通过adjustLayoutParamsForSubWindows设置的,它会根据不同的窗口类型和属性设置该token.
  2. 如果未取到WindowToken需要为其创建一个。
  3. 随后为该窗口创建WindowState,它代表了应用端的Window。同时将其添加到mWindowMap中
  4. 根据不同的窗口类型设置窗口的Z序。

关于添加窗口的具体细节,这里就不详述,我会在后面的文章后介绍。

显示的时机

在handleResumeActivity通过addView添加view,将window加入到WMS后,会通过updateViewLayout更新视图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
frameworks/base/core/java/android/view/WindowManagerGlobal.java
//更新视图
public void updateViewLayout(View view, ViewGroup.LayoutParams params) {
if (view == null) {
throw new IllegalArgumentException("view must not be null");
}
if (!(params instanceof WindowManager.LayoutParams)) {
throw new IllegalArgumentException("Params must be WindowManager.LayoutParams");
}

final WindowManager.LayoutParams wparams = (WindowManager.LayoutParams)params;

view.setLayoutParams(wparams);//设置view布局参数

synchronized (mLock) {
int index = findViewLocked(view, true);
ViewRootImpl root = mRoots.get(index);//找到对应的viewroot
mParams.remove(index);//移除之前的params
mParams.add(index, wparams);//添加新的params
root.setLayoutParams(wparams, false);//通过root设置参数 false代表view已经添加过 这里会对view树重新绘制
}
}

在root.setLayoutParams中会通过scheduleTraversals()绘制view。

坚持原创技术分享,您的支持将鼓励我继续创作!